package com.shangxia.dreaming.business;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import com.shangxia.dreaming.business.pojo.Model;
import com.shangxia.dreaming.business.pojo.Model2;
import com.shangxia.dreaming.business.pojo.SecondModel;
import com.shangxia.dreaming.common.content.ConditionContent;
import com.shangxia.dreaming.common.content.FileContentEnum;
import com.shangxia.dreaming.common.util.excelUtil.HeadFactory;
import com.shangxia.dreaming.common.util.excelUtil.WriteExcel;
import com.shangxia.dreaming.common.util.excelUtil.WriteHandler.MyEasyWriteHandler;
import com.shangxia.dreaming.common.util.excelUtil.WriteHandler.MyPurpleAllWriteHandler;
import com.shangxia.dreaming.common.util.excelUtil.WriteHandler.MyPurpleAllWriteHandler2;
import com.shangxia.dreaming.common.util.txtUtil.ReadTXT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

import static com.shangxia.dreaming.common.content.ConditionContent.*;

/**
 * @ProjectName: dreaming
 * @ClassName: SecondJob
 * @Time: 2020/10/10
 * @Author: zhouy
 * @Description:
 * @Experience:
 */

@Slf4j
@Component
public class FiveJob {
    @Resource
    private PrePareJob prePareJob = new PrePareJob();
    private static Integer qi_shu;

    public void work() throws Exception {

        //读取真号
        List<List<Integer>> realCodeLists = ReadTXT.readList_List_int();
        qi_shu = realCodeLists.size();
        List<List<Integer>> realCodeLists1 = new ArrayList<>();
        List<List<Integer>> realCodeLists2 = new ArrayList<>();
        List<List<Integer>> realCodeLists3 = new ArrayList<>();
        for (int i = 0; i < realCodeLists.size(); i++) {
            ArrayList<Integer> list1 = new ArrayList<>();
            ArrayList<Integer> list2 = new ArrayList<>();
            ArrayList<Integer> list3 = new ArrayList<>();
            List<Integer> list = realCodeLists.get(i);
            list1.add(list.get(0));
            list2.add(list.get(1));
            list3.add(list.get(2));
            realCodeLists1.add(list1);
            realCodeLists2.add(list2);
            realCodeLists3.add(list3);
        }

        //最大翻表层数
        int limit = Math.min(realCodeLists.size(), MUST_TURN_TABLE_COLUMN);
        log.info("计算层数=" + limit);
        //翻表
        log.info("开始翻层");
        List<Integer>[][] arr1 = prePareJob.turnTable0(realCodeLists1, realCodeLists1.size(), 1, SUM_CODE_LENGTH);
        List<Integer>[][] arr2 = prePareJob.turnTable0(realCodeLists2, realCodeLists2.size(), 1, SUM_CODE_LENGTH);
        List<Integer>[][] arr3 = prePareJob.turnTable0(realCodeLists3, realCodeLists3.size(), 1, SUM_CODE_LENGTH);
        log.info("翻层结束");
        if (false) {
            WriteExcel.exportRangeColumnExcel(arr1, 1, 10, 1, 10, 0);
            WriteExcel.exportRangeColumnExcel(arr2, 1, 10, 1, 10, 2);
            WriteExcel.exportRangeColumnExcel(arr3, 1, 10, 1, 10, 3);
        }

        List<List<Model>> modelLists = new ArrayList<>();
        for (int i = 0; i < limit; i++) {
            List<Model> modelList = new ArrayList<>();
            modelLists.add(initModelList(modelList, i));
        }
        log.info("位置准备结束");
        List<List<String>> resultLists = new ArrayList<>();
        List<List<String>> serResultLists = new ArrayList<>();
        int maxSize = 0;
        int maxSecondSize = 0;

        Map<String, SecondModel> secondTrueMap = new HashMap<>();
        List<Integer> firstAgeList = new ArrayList<>();
        List<Integer> secondAgeList = new ArrayList<>();

        for (int row = 0; row < qi_shu - 1; row++) {
            List<String> secondList = new ArrayList<>();
            if (row % 100 == 0) {
                log.info("计算第" + (row + 1) + "期");
            }
            List<Model> trueModels = new ArrayList<>();
            Boolean flag = true;
            int columnLimit = Math.min(row, limit - 1);
            for (int column = 0; column <= columnLimit; column++) {
                List<Model> modelList = modelLists.get(column);
                Integer realCode = arr1[row + 1][column].get(9);
                List<Integer> list1 = arr1[row][column];
                int index1 = getIndex(realCode, list1);
                int groupIndex1 = groupIndex(index1);
                int index2 = getIndex(arr2[row + 1][column].get(9), arr2[row][column]);
                int groupIndex2 = groupIndex(index2);
                int index3 = getIndex(arr3[row + 1][column].get(9), arr3[row][column]);
                int groupIndex3 = groupIndex(index3);
                for (Model model : modelList) {
                    model.setRow(row);
                    if (flag && (groupIndex1 + "," + groupIndex2 + "," + groupIndex3).equals(model.getGroupIndexStr())) {
                        model.setFlag(true);
                        flag = false;
                    }
                    model.setAge(model.getAge() + 1);
                    String key = column + "-" + model.getGroupIndexStr();

                    if (secondTrueMap.containsKey(key)) {
                        int age = model.getRow() - secondTrueMap.get(key).getRow();
                        if (secondList.size() == 0) {
                            secondList.add(row + 1 + "");
                        }
                        setRealIndexStr(model, arr1, arr2, arr3);
                        secondList.add(model.getGroupIndexStr());
                        secondList.add(""+age);
                        secondList.add(model.getRealIndexStr() + "");
                        secondList.add(model.getColumn() + "");
                        secondList.add("" + model.getFlag());
                        if (model.getFlag()){
                            secondTrueMap.get(key).setFlag(false);
                            secondTrueMap.remove(key);
                            secondAgeList.add(age);
                        }
                    }

                    if (model.getAge() >= MIN_COUNT_AGE) {
                        model.setIndexStr(index1 + "," + index2 + "," + index3);
                        setRealIndexStr(model, arr1, arr2, arr3);
                        Model model0 = new Model();
                        BeanUtils.copyProperties(model, model0);
                        trueModels.add(model0);
                        if (model.getFlag()) {
                            firstAgeList.add(model.getAge());
                            secondTrueMap.put(key, new SecondModel(model.getRow(), true));
                        }
                    }

                    if (model.getFlag()) {
                        model.setAge(0);
                        model.setFlag(false);
                    }

                }
                flag = true;
            }
            if (secondList.size() > 0) {
                maxSecondSize = secondList.size() / 5;
                serResultLists.add(secondList);
            }
            if (trueModels.size() > 2000) {
                log.error("请增加最小年龄");
                Thread.sleep(10000);
                System.exit(0);
            }
            if (row > MIN_COUNT_AGE && trueModels.size() > 0) {
                List<String> list = new ArrayList<>();
                list.add(row + 1 + "");
                trueModels.sort((o1, o2) -> o2.getAge() - o1.getAge());
                for (Model model : trueModels) {
                    list.add(model.getGroupIndexStr());
                    list.add(model.getAge() + "");
                    list.add(model.getRealIndexStr() + "");
                    list.add(model.getColumn() + "");
                    list.add("" + model.getFlag());
                }
                maxSize = Math.max(maxSize, trueModels.size());
                resultLists.add(list);
            }
        }
        log.info("预测最后一期");
        //预测最后一期
        List<String> list = resultLists.get(resultLists.size() - 1);
        List<String> lastList = new ArrayList<>();
        lastList.add(Integer.parseInt(list.get(0)) + 1 + "");
        for (int i = 1; i < list.size(); i = i + 5) {
            if ("true".equals(list.get(i + 4))) {
                continue;
            }
            String indexStr = list.get(i);
            //位置
            lastList.add(indexStr);
            //年龄
            lastList.add(Integer.parseInt(list.get(i + 1)) + 1 + "");
            //
            String[] split = indexStr.split(",");
            Integer column = Integer.parseInt(list.get(i + 3));
            Integer code11 = getRealCode(column, arr1[arr1.length - 1], split[0], 0);
            Integer code12 = getRealCode(column, arr1[arr1.length - 1], split[0], 1);
            Integer code21 = getRealCode(column, arr2[arr2.length - 1], split[1], 0);
            Integer code22 = getRealCode(column, arr2[arr2.length - 1], split[1], 1);
            Integer code31 = getRealCode(column, arr3[arr3.length - 1], split[2], 0);
            Integer code32 = getRealCode(column, arr3[arr3.length - 1], split[2], 1);
            //真号
            lastList.add(code11 + "," + code12 + "-" + code21 + "," + code22 + "-" + code31 + "," + code32);
            //层数
            lastList.add("" + Integer.parseInt(list.get(i + 3)));
            //空
            lastList.add(" ");
        }
        resultLists.add(lastList);
        //相对最后一期中奖数据
        log.info("计算完成，输出结果");
        saveResult(resultLists, maxSize, "超过结果");

        orderResultList(serResultLists);
        saveResult2(serResultLists, maxSecondSize, "第二次超过结果");

        saveAgeCountList("年龄统计结果", getAgeResult(firstAgeList), getAgeResult(secondAgeList));
    }

    private void orderResultList(List<List<String>> serResultLists) {
        for (int i = 0; i < serResultLists.size(); i++) {
            List<String> list = serResultLists.get(i);
            String index0 = list.get(0);
            if (list.size() > 5) {
                List<Model2> list1 = new ArrayList<>();
                for (int j = 1; j < list.size(); j += 5) {
                    list1.add(new Model2(list.get(j), list.get(j + 1), list.get(j + 2), list.get(j + 3), list.get(j + 4)));
                }
                list1.sort((o1, o2) -> Integer.parseInt(o2.getAge()) - Integer.parseInt(o1.getAge()));
                serResultLists.remove(i);
                List<String> list0 = new ArrayList<>();
                list0.add(index0);
                for (Model2 model2 : list1) {
                    list0.add(model2.getIndex());
                    list0.add(model2.getAge());
                    list0.add(model2.getRealCode());
                    list0.add(model2.getColumn());
                    list0.add(model2.getFlag());
                }
                serResultLists.add(i, list0);
            }
        }
    }

    private void saveAgeCountList(String fileName, List<List<Integer>> ageFirstResult, List<List<Integer>> ageSecondResult) {
        File file = new File(PATH_Result + fileName + ".xlsx");
        if (file.exists()) {
            file.delete();
        }
        ExcelWriter excelWriter = EasyExcel.write(file).registerWriteHandler(new MyEasyWriteHandler()).head(HeadFactory.head22()).build();
        WriteSheet writeSheet0 = EasyExcel.writerSheet(0, "第一次年龄统计结果").build();
        WriteSheet writeSheet1 = EasyExcel.writerSheet(1, "第二次年龄统计结果").build();
        excelWriter.write(ageFirstResult, writeSheet0);
        excelWriter.write(ageSecondResult, writeSheet1);
        if (excelWriter != null) {
            excelWriter.finish();
        }
    }

    private List<List<Integer>> getAgeResult(List<Integer> firstAgeList) {
        List<List<Integer>> lists = new ArrayList<>();
        Map<Integer, List<Integer>> collect = firstAgeList.stream().collect(Collectors.groupingBy(integer -> integer, Collectors.toList()));
        List<Integer> sortList = new ArrayList<>(collect.keySet());
        sortList.sort((o1, o2) -> o2 - o1);
        for (Integer age : sortList) {
            List<Integer> list = new ArrayList<>();
            list.add(age);
            list.add(collect.get(age).size());
            lists.add(list);
        }
        return lists;
    }

    private int getIndex(Integer realCode, List<Integer> list5) {
        List<Integer> list = list5;
        return list.indexOf(realCode);
    }

    private void setRealIndexStr(Model model, List<Integer>[][] arr1, List<Integer>[][] arr2, List<Integer>[][] arr3) {
        String[] split = model.getGroupIndexStr().split(",");
        Integer code11 = getRealCode(model.getColumn(), arr1[model.getRow()], split[0], 0);
        Integer code12 = getRealCode(model.getColumn(), arr1[model.getRow()], split[0], 1);
        Integer code21 = getRealCode(model.getColumn(), arr2[model.getRow()], split[1], 0);
        Integer code22 = getRealCode(model.getColumn(), arr2[model.getRow()], split[1], 1);
        Integer code31 = getRealCode(model.getColumn(), arr3[model.getRow()], split[2], 0);
        Integer code32 = getRealCode(model.getColumn(), arr3[model.getRow()], split[2], 1);
        model.setRealIndexStr(code11 + "," + code12 + "-" + code21 + "," + code22 + "-" + code31 + "," + code32);
    }

    private Integer getRealCode(Integer column, List<Integer>[] lists, String s, Integer ji) {
        Integer code11 = lists[column].get(2 * (Integer.parseInt(s) - 1) + ji);
        while (column > 0) {
            column--;
            code11 = lists[column].get(code11);
        }
        return code11;
    }

    private List<Model> initModelList(List<Model> modelList, int column) {
        for (int i = 1; i < 6; i++) {
            for (int j = 1; j < 6; j++) {
                for (int k = 1; k < 6; k++) {
                    modelList.add(new Model(i + "," + j + "," + k, column));
                }
            }
        }
        return modelList;
    }

    private void saveResult(List<List<String>> resultLists, int maxSize, String fileName) {
        File file = new File(PATH_Result + fileName + FileContentEnum.EXCEL_END);
        if (file.exists()) {
            file.delete();
        }
        EasyExcel.write(file).head(HeadFactory.head1(maxSize)).sheet("超过结果").registerWriteHandler(new MyPurpleAllWriteHandler()).doWrite(resultLists);
    }

    private void saveResult2(List<List<String>> resultLists, int maxSize, String fileName) {
        File file = new File(PATH_Result + fileName + FileContentEnum.EXCEL_END);
        if (file.exists()) {
            file.delete();
        }
        EasyExcel.write(file).head(HeadFactory.head1(maxSize)).sheet("超过结果").registerWriteHandler(new MyPurpleAllWriteHandler2()).doWrite(resultLists);
    }

    private int groupIndex(int index) {
        switch (index) {
            case 0:
            case 1:
                return 1;
            case 2:
            case 3:
                return 2;
            case 4:
            case 5:
                return 3;
            case 6:
            case 7:
                return 4;
            default:
                return 5;
        }
    }


}
